//own libraries
#include "initialiseArraysSerial.h"
#include "initialiseArraysParallel.h"
#include "PrinterConverter.h"
#include "main.h"
#include "CollectResults.h"

//tbb libraries
#include "tbb/task_scheduler_init.h"
#include "tbb/parallel_sort.h"
#include "tbb/partitioner.h"
#include "tbb/parallel_for.h"

//std libraries
#include <algorithm>
#include <vector>
#include <time.h>

//prototypes
void initScheduler();
void initCollectors();
void calculateAverages();

//data arrays
float arraySerialCalculation[sizeOfArray];
float arrayParallelCalculation[sizeOfArray];

std::vector<CollectResults> collectors; 

int main()
{
	initScheduler();
	initCollectors();
	initialiseArraysSerial serialInit = initialiseArraysSerial();

	
	
	for(int index_iterations = 0; index_iterations < iterations; index_iterations++)
	{
		for(int index_collectors = 0; index_collectors < collectors.size(); index_collectors++)
		{
			//serial initialise
			if(collectors.at(index_collectors).getName().compare(SerialInitExecutionTime) == 0)
			{
				collectors.at(index_collectors).start();//starttime 
				
				serialInit.initialise(arraySerialCalculation,sizeOfArray);
				
				collectors.at(index_collectors).stop();//endtime serial 
			}
			if(collectors.at(index_collectors).getName().compare(ParallelInitExecutionTime) == 0)
			{
				collectors.at(index_collectors).start();//starttime parallel init
				parallel_for(tbb::blocked_range<size_t>(0,sizeOfArray), initialiseArraysParallel(arrayParallelCalculation), 
					tbb::auto_partitioner());//parallel init
				//parallel_for(tbb::blocked_range<size_t>(0,sizeOfArray,40), initialiseArraysParallel(arrayParallelCalculation));//parallel init
				collectors.at(index_collectors).stop();//endtime parallel 
			}
			if(collectors.at(index_collectors).getName().compare(SerialExecutionTime) == 0)
			{
				collectors.at(index_collectors).start();//starttime serial sort
				std::sort(arraySerialCalculation, arraySerialCalculation+sizeOfArray);
				collectors.at(index_collectors).stop();//endtime serial sort
			}
			if(collectors.at(index_collectors).getName().compare(ParallelExecutionTime) == 0)
			{
				collectors.at(index_collectors).start();//starttime parallel sort
				tbb::parallel_sort(arrayParallelCalculation,arrayParallelCalculation+sizeOfArray);
				collectors.at(index_collectors).stop();//endtime parallel sort
			}
		}
			
	}
	calculateAverages();
	PrinterConverter converter = PrinterConverter();
	converter.extractValuesFromCollector(iterations, sizeOfArray, &collectors);
	converter.printToScreen();//print to screen
	converter.printToFile();//print to file

	std::cin.get();
	return 0;
}

void initScheduler()
{
	tbb::task_scheduler_init tbb_task_scheduler_init(tbb::task_scheduler_init::deferred); //always init the task scheduler
	tbb_task_scheduler_init.initialize(3);//specify the number of threads
}

void initCollectors()
{
	//create result collector objects
	collectors.push_back(CollectResults(ParallelExecutionTime, ParallelExecutionTimeDesc));
	collectors.push_back(CollectResults(SerialExecutionTime, SerialExecutionTimeDesc));

	collectors.push_back(CollectResults(ParallelInitExecutionTime, ParallelInitExecutionTimeDesc));
	collectors.push_back(CollectResults(SerialInitExecutionTime, SerialInitExecutionTimeDesc));
}

void calculateAverages()
{
	for(int index_collectors = 0; index_collectors < static_cast<int>(collectors.size()); index_collectors++)
	{
		collectors.at(index_collectors).calculateAverages();
	}
}